package com.liuyun.asymmetric.rsa;

import java.security.Key;
import java.util.Arrays;
import java.util.Map;

import static com.liuyun.asymmetric.rsa.RsaUtil.getPrivateKey;
import static com.liuyun.asymmetric.rsa.RsaUtil.getPublicKey;

/**
 * <p>
 * Copyright: (C), 2021/1/27 22:43
 * <p>
 * <p>
 * Company Information & Data Security Solutions Co., Ltd.
 *
 * @author LiuYun liujw@idss-cn.com
 * @version 1.0
 */
public class RsaBlockCipherUtil {
    // 单次加密数据最大字节数：仅仅适用于【密钥=1024 填充模式=PKCS1Padding】
    public static final int DATA_LEN = 117;
    // 单词加密后的密文字节数/单次解密要求的密文字节数：仅仅适用于【密钥=1024 填充模式=PKCS1Padding】
    public static final int BLOCK_BYTE_SIZE = 128;

    /**
     * 分段加密
     *
     * @param plaintextBytes 明文字节数组
     * @param keyMap         私钥钥池
     * @param blockByteSize  单词加密后的密文字节数
     * @param dataLen        单次加密数据最大字节数
     * @return
     */
    public static byte[] multiEncrypt(byte[] plaintextBytes, Map<String, Key> keyMap, int blockByteSize, int dataLen) {
        final int plainLen = plaintextBytes.length;
        int count = plainLen / dataLen;
        if (plainLen % dataLen > 0) {
            count++;
        }
        System.out.println("count=" + count);
        // 分段加密
        byte[] encrypts = new byte[(count * blockByteSize)];
        for (int i = 0; i < count; i++) {
            int to = (i + 1) * dataLen > plainLen ? plainLen : (i + 1) * dataLen;
            byte[] data = Arrays.copyOfRange(plaintextBytes, i * dataLen, to);
            byte[] encrypt = RsaUtil.encryptByPrivateKey(data, getPrivateKey(keyMap));
            System.arraycopy(encrypt, 0, encrypts, i * blockByteSize, encrypt.length);
        }
        return encrypts;
    }

    /**
     * 分段解密
     *
     * @param encrypts      代解密的明文字节数组
     * @param keyMap        公钥池
     * @param blockByteSize 单次解密要求的密文字节数
     * @param dataLen       单次加密数据最大字节数
     * @return
     */
    public static byte[] multiDecrypt(byte[] encrypts, Map<String, Key> keyMap, int blockByteSize, int dataLen) {
        if (encrypts.length == 0) {
            return null;
        }
        if (encrypts.length % blockByteSize != 0) {
            throw new RuntimeException("密文字节数必须为" + blockByteSize + "的整数倍");
        }
        int count = encrypts.length / blockByteSize;
        // 分段解密
        byte[] decrypts = new byte[(count * dataLen)];
        int lastDataLen = 0;
        for (int i = 0; i < count; i++) {
            byte[] data = Arrays.copyOfRange(encrypts, i * blockByteSize, (i + 1) * blockByteSize);
            byte[] decrypt = RsaUtil.decryptByPublicKey(data, getPublicKey(keyMap));
            System.arraycopy(decrypt, 0, decrypts, i * dataLen, decrypt.length);
            lastDataLen = decrypt.length;
        }
        return Arrays.copyOfRange(decrypts, 0, decrypts.length + lastDataLen - dataLen);
    }

    /**
     * 分段加密
     * 仅适用于【密钥=1024 填充模式=PKCS1Padding】
     *
     * @param plaintextBytes 明文字节数组
     * @param keyMap         私钥钥池
     * @return
     */
    public static byte[] multiEncrypt(byte[] plaintextBytes, Map<String, Key> keyMap) {
        return multiEncrypt(plaintextBytes, keyMap, BLOCK_BYTE_SIZE, DATA_LEN);
    }

    /**
     * 分段解密
     * 仅适用于【密钥=1024 填充模式=PKCS1Padding】
     *
     * @param encrypts 代解密的明文字节数组
     * @param keyMap   公钥池
     * @return
     */
    public static byte[] multiDecrypt(byte[] encrypts, Map<String, Key> keyMap) {
        return multiDecrypt(encrypts, keyMap, BLOCK_BYTE_SIZE, DATA_LEN);
    }
}
